String temp; //保存温度
String humi; //保存湿度

//等待对应引脚高/低电平结束，返回等待时间（us）
int waitPulse(int pin, int level)
{
  int count = 0;

  while (digitalRead(pin) == level)
  {
    delayMicroseconds(1);
    count++;
    if (count > 1000) break;  //1ms超时处理
  }

  return count;
}

void dht_read(int pin)
{
  char data[5];  //保存从DHT11传感器中读出的数据40bit
  pinMode(pin, OUTPUT);  //将对应数据引脚设置为输出模式
  digitalWrite(pin, LOW); //在数据线上输出低电平
  delay(20);  //低电平维持18ms以上
  //将数据线上的电平拉高（开始信号结束），并等待DHT11响应（拉低数据线上的电平）
  pinMode(pin, INPUT_PULLUP);
  delayMicroseconds(40); //等DHT11响应 20 ~ 40us
  //等待低电平结束80us
  if (waitPulse(pin, LOW) == 0) //传感器没有响应
  {
    Serial.println("no response");
    return;
  }
  //等待高电平结束80us
  waitPulse(pin, HIGH);
  //接收第一个bit位
  for (int i = 0; i < 40; i++)
  {
    data[i/8] <<= 1;
    int low_time = waitPulse(pin, LOW);
    int high_time = waitPulse(pin, HIGH);
    if (high_time > low_time)
    {
      data[i/8] |= 1; //将第一个字节的第一个bit位设置为1
      //位或
      // 1010 1010
      // 0000 0001
      //-----------或
      // 1010 1011
    }
    else
    {
      data[i/8] &= ~1; //将第一个字节的第一个bit位设置为0
      //位与
      // 1010 1011
      // 1111 1110 0xFE=~1 按位取反
      //-----------与
      // 1010 1010
    }
  }

  waitPulse(pin, LOW); //当最后一bit数据传送完毕后，DHT11拉低总线50us

  char chksum = data[0] + data[1] + data[2] + data[3]; //计算校验和
  if (chksum != data[4]) //数据错误
  {
    return;
  }

  humi = String((int)data[0]) + "." + String((int)data[1]);
  temp = String((int)data[2]) + "." + String((int)data[3]);
}

void setup() {
  Serial.begin(74880);
  pinMode(D1, INPUT_PULLUP); //数据总线空闲时保持高电平
  delay(1000); //等待1s，越过不稳定状态
}

void loop() {
  dht_read(D1);
  String s = "温度:" + temp + ",湿度:" + humi;  //在串口绘图器上画线
  Serial.println(s);
  delay(1200); //少于1200ms部分传感器不能成功响应
}
